package MelbourneMap;

import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;

/**
 * Node object used to represent a point in a {@link Region}
 * and also a node in a {@link Graph}. Node extends Point2D
 * and is similar in many ways. It also implements Comparable
 * so that it is compatible with {@link PriorityQueue} and can
 * therefore be used in path searching algorithms.
 * 
 * @author David Zappia, 7183216
 * @author Heong Jin Yu, 7019777
 *
 */
public class Node extends Point2D implements Comparable<Node>
{
	private int ID;
	private double xPos, yPos;
	private Shape shape;
	private ArrayList<Edge> edgeList;
	private ArrayList<Region> regionList;
	private double pathCost;
	private final int SHAPE_DIAM = 50;
	public boolean editable;
	
	/**
	 * Constructor for Node taking an id and x and y
	 * positions for the Node.
	 * 
	 * @param id	the unique node ID
	 * @param x		the x position of the node
	 * @param y		the y position of the node
	 */
	public Node(int id, double x, double y)
	{
		ID = id;
		xPos = x;
		yPos = y;
		edgeList = new ArrayList<Edge>();
		regionList = new ArrayList<Region>();
		pathCost = 0.0;
		shape = new Ellipse2D.Double(xPos-SHAPE_DIAM/2, yPos-SHAPE_DIAM/2, SHAPE_DIAM, SHAPE_DIAM);
	}
	
	@Override
	public double getX() 
	{
		return xPos;
	}
	
	@Override
	public double getY() 
	{
		return yPos;
	}
	
	@Override
	public void setLocation(double x, double y) 
	{
		xPos = x;
		yPos = y;		
	}
	
	/**
	 * Gives the node a reference to an {@link Edge} that
	 * it is a part of so that it can inform the edge
	 * to recalculate it's cost when the Node has been 
	 * moved.
	 * 
	 * @param e		the edge that this node is a part of
	 */
	public void addEdge(Edge e)
	{
		edgeList.add(e);
	}
	
	/**
	 * Gives the node a reference to a {@link Region} that
	 * it is a part of so that the node can inform
	 * the region to rebuild it's shape.
	 * 
	 * @param r		the region that this node is a part of
	 */
	public void addRegion(Region r)
	{
		regionList.add(r);
	}
	
	/**
	 * Sets the node ID to a new ID. This ID should be unique
	 * if nodes are to be used in a graph.
	 * 
	 * @param newID		the new unique ID for the node
	 */
	public void setID(int newID)
	{
		ID = newID;
	}
	
	/**
	 * Gets the unique ID of the node. Useful for 
	 * locating edges in a {@link Graph}.
	 * 
	 * @return		the unique ID of the node
	 */
	public int getID()
	{
		return ID;
	}
	
	/**
	 * Gets the Shape object relating to this node.
	 * To be used when drawing the node.
	 * 
	 * @return		the Shape object relating to the node
	 * @see			Shape
	 */
	public Shape getShape()
	{
		return shape;
	}
	
	/**
	 * Sets the path cost relating to this node.
	 * Used by path planning algorithms to determine
	 * how to treat this node.
	 * <p>
	 * Synchronised so for thread safety.
	 * 
	 * @param cost		the path cost for this node
	 */
	public synchronized void setPathCost(double cost)
	{
		pathCost = cost;
	}
	
	/**
	 * Gets the path cost relating to this node.
	 * Used by path planning algorithms to determine
	 * how to treat this node.
	 * <p>
	 * Synchronised for thread safety.
	 * 
	 * @return		the path cost for this node
	 */
	public synchronized Long getPathCost()
	{
		return (long) pathCost;
	}
	
	/**
	 * Compares two nodes based on their cost
	 * in the current path being planned.
	 */
	@Override
	public int compareTo(Node other)
	{
		Long cost = (long) pathCost;
		if (cost.compareTo(other.getPathCost()) > 0 )
			return 1;
		else
			return -1;
	}
	
	/**
	 * Updates the Node's position and informs all
	 * of the {@link Region} and {@link Edge} objects
	 * related to this Node that they need to be updated
	 */
	public void update()
	{
		for(Region r : regionList)
			r.rebuildShape();
		for(Edge e : edgeList)
			e.calcCost();
		shape = new Ellipse2D.Double(xPos-SHAPE_DIAM/2, yPos-SHAPE_DIAM/2, SHAPE_DIAM, SHAPE_DIAM);
	}
}